#!/usr/bin/env python
## lighthouse.py -- Script to integrate with Lighthouse -*- Python -*-
## Time-stamp: "2008-08-05 21:24:37 ghoseb"

#===============================================================================
# Copyright (c) Baishampayan Ghose.
# All rights reserved.

# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:

#     1. Redistributions of source code must retain the above copyright notice, 
#        this list of conditions and the following disclaimer.
    
#     2. Redistributions in binary form must reproduce the above copyright 
#        notice, this list of conditions and the following disclaimer in the
#        documentation and/or other materials provided with the distribution.

#     3. Neither the name of Django nor the names of its contributors may be used
#        to endorse or promote products derived from this software without
#        specific prior written permission.

# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#=================================================================================

import os
import re
import sys
import StringIO
from httplib2 import Http
from subprocess import Popen, PIPE

def command_output(*args):
    '''Return the result of executing args
    '''
    args = map(str, args)
    try:
        return Popen(args, stdout=PIPE).communicate()[0][:-1:]
    except OSError:
        return None

SVNLOOK = command_output('which', 'svnlook')

# Tokens have to be added for each SVN committer for Lighthouse to be
# able to correctly identify the user in the changeset.
# http://lighthouseapp.com/help/setting-up-subversion-integration

OPTIONS = {'tokens': {'user':'TOKEN',
           'account': 'http://xxx.lighthouseapp.com',
           'project': 'PROJECT_ID', # Project ID
           'prefix': None}
USER_AGENT = 'My Own User Agent 1.0'

def sanitize_date(datestring):
    '''Sanitize a datestring to one accepted by Lighthouse
    '''
    d = datestring.split('(')[0].split()
    o = StringIO.StringIO()
    print >>o, "%sT%s%s" % (d[0], d[1], d[2])
    try:
        return o.getvalue()[:-1:]
    finally:
        o.close()

def sanitize_changes(changelist):
    '''Sanitize the Changes list
    '''
    try:
        changes = changelist.split('\n')
    except AttributeError:
        changes = changelist
    o = StringIO.StringIO()
    print >>o, "---"
    for change in changes:
        c = change.split()
        print >>o, "- - %s\n  - %s" % (c[0], c[1])
    try:
        return o.getvalue()[:-1:]
    finally:
        o.close()
        
def post_to_lighthouse(data, options, author):
    '''Post the data to Lighthouse
    '''
    token = options['tokens'][author]
    if not token:
        token = options['tokens']['xxx'] # Change this to some username
    o = StringIO.StringIO()
    print >>o, "%s/projects/%s/changesets.xml" % (options['account'], options['project'])
    url = o.getvalue()[:-1:]
    o.close()
    h = Http()
    response, content = h.request(url, "POST", body=data, headers={'User-Agent':USER_AGENT, 'X-LighthouseToken':token,
                                                                   'Content-Type':'application/xml'})
    return content
    

def construct_changeset(*args, **kwargs):
    '''Construct the Changeset XML
    '''
    output = StringIO.StringIO()
    print >>output, "<changeset>"
    print >>output, "  <title>%s committed changeset [%s]</title>" % (kwargs['author'], kwargs['revision'])
    print >>output, "  <body>%s</body>" % kwargs['log']
    print >>output, "  <changes>%s\n  </changes>" % kwargs['changes']
    print >>output, "  <revision>%s</revision>" % kwargs['revision']
    print >>output, "  <changed-at type=\"datetime\">%s</changed-at>" % sanitize_date(kwargs['date'])
    print >>output, "</changeset>"
    try:
        return output.getvalue()[:-1:]
    finally:
        output.close()
        
def post_changeset(path, revision, options=OPTIONS):
    '''Get all the information about the commit and post the info to
    lighthouse
    '''
    if OPTIONS['prefix']:
        commit_dirs_changed = command_output(SVNLOOK, 'dirs-changed', path, '-r', revision)
        if not OPTIONS['prefix'].match(commit_dirs_changed.split('\n')[0]):
            print commit_dirs_changed.split('\n')[0]
            return
    commit_author = command_output(SVNLOOK, 'author', path, '-r', revision)
    commit_log = command_output(SVNLOOK, 'log', path, '-r', revision)
    commit_date = command_output(SVNLOOK, 'date', path, '-r', revision)
    commit_changed = command_output(SVNLOOK, 'changed', path, '-r', revision)

    commit_changes = sanitize_changes(commit_changed.split('\n'))

    changeset = construct_changeset(revision=revision, author=commit_author,
                                    log=commit_log, date=commit_date,
                                    changes=commit_changes)

    return post_to_lighthouse(changeset, OPTIONS, commit_author)


if __name__=='__main__':
    post_changeset(sys.argv[1], sys.argv[2])
